package com.gdth.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.Date;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.gdth.core.annotation.table.Column;
import com.gdth.core.annotation.table.Id;
import com.gdth.core.annotation.table.Table;

/**
 * Class tools
 * @author Arvin
 *
 */
public class ClassUtil {
	
	/**
	 * 动态创建实体类
	 * @param model
	 * @return
	 */
	public static Object newInstance(Object model){
		Object instance = null;
		try {
			Class<?> aClass = model.getClass();
			
			instance = aClass.newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return instance;
	}
	
	/** 
     * 执行set方法 
     *  
     * @param o 执行对象 
     * @param fieldName 属性 
     * @param value 值 
     */  
    public static void invokeSet(Object o, String fieldName, Object value) {  
        Method method = getSetMethod(o.getClass(), fieldName);  
        try {  
            method.invoke(o, new Object[] { value });  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    } 
				
	/** 
     * java反射bean的set方法 
     *  
     * @param objectClass 
     * @param fieldName 
     * @return 
     */   
    public static Method getSetMethod(Class<?> objectClass, String fieldName) {  
        try {  
            Class<?>[] parameterTypes = new Class[1];
            
            Field field = objectClass.getDeclaredField(fieldName);  
            
            parameterTypes[0] = field.getType();  
            StringBuffer sb = new StringBuffer();  
            sb.append("set");  
            sb.append(StringUtil.getUpperCase(fieldName.substring(0, 1)));  
            sb.append(fieldName.substring(1));  
            
            Method method = objectClass.getMethod(sb.toString(), parameterTypes);  
            return method;  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return null;  
    }
    
    /** 
     * 执行get方法 
     *  
     * @param o 执行对象 
     * @param fieldName 属性 
     */  
//    public static Object invokeGet(Object o, String fieldName) {  
//        Method method = getGetMethod(o.getClass(), fieldName);  
//        try {  
//            return method.invoke(o, new Object[0]);  
//        } catch (Exception e) {  
//            e.printStackTrace();  
//        }  
//        return null;  
//    }  
    
	public void dd (Object model) throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		Field[] field = model.getClass().getDeclaredFields();        //获取实体类的所有属性，返回Field数组 
		
		int length = field.length;
        for (int j = 0; j < length; j++){     //遍历所有属性
        	String name = field[j].getName();    //获取属性的名字
        	
        	name = name.replaceFirst(name.substring(0, 1), StringUtil.getUpperCase(name.substring(0, 1)));

//            System.out.println("attribute name:"+name);  
            
            String type = field[j].getGenericType().toString();    //获取属性的类型
            
			if(type.equals("class java.lang.String")){   //如果type是类类型，则前面包含"class "，后面跟类名
		        Method m = model.getClass().getMethod("get"+name);
		        
		        String value = (String) m.invoke(model);    //调用getter方法获取属性值
		        
		        if(value != null){
//		            System.out.println("attribute value:"+value);
		        }
		    }
		    if(type.equals("class java.lang.Integer")){     
		        Method m = model.getClass().getMethod("get"+name);
		        Integer value = (Integer) m.invoke(model);
		        if(value != null){
//		            System.out.println("attribute value:"+value);
		        }
		    }
		    if(type.equals("class java.lang.Short")){     
		        Method m = model.getClass().getMethod("get"+name);
		        Short value = (Short) m.invoke(model);
		        if(value != null){
//		            System.out.println("attribute value:"+value);                    
		        	}
		    }       
		    if(type.equals("class java.lang.Double")){     
		        Method m = model.getClass().getMethod("get"+name);
		        Double value = (Double) m.invoke(model);
		        if(value != null){                    
//		            System.out.println("attribute value:"+value);  
		        }
		    }                  
		    if(type.equals("class java.lang.Boolean")){
		        Method m = model.getClass().getMethod("get"+name);    
		        Boolean value = (Boolean) m.invoke(model);
		        if(value != null){                      
//		            System.out.println("attribute value:"+value);
		        }
		    }
		    if(type.equals("class java.util.Date")){
		        Method m = model.getClass().getMethod("get"+name);                    
		        Date value = (Date) m.invoke(model);
		        if(value != null){
		        }
		    } 
        }
	}
	
	/**
	 * 
	 * @param arg0
	 * @return
	 */
	public static String getTableName(Class<?> arg0) {
		Table table = arg0.getAnnotation(Table.class);
		if(table == null || table.name().trim().length() == 0 ){
			return arg0.getName().replace('.', '_');
		}
		
		return table.name();
	}
	
	public static Object getFieldValue(Object entity,Field arg0){
		Method method = getFieldGetMethod(entity.getClass(), arg0);
		return invoke(entity, method);
	}
	
	public static Object getFieldValue(Object entity,String arg0){
		Method method = getFieldGetMethod(entity.getClass(), arg0);
		return invoke(entity, method);
	}
	
	/**
	 * 
	 * @param arg0
	 * @param arg1
	 * @return
	 */
	public static Method getFieldGetMethod(Class<?> arg0, Field arg1) {
		String fn = arg1.getName();
		Method mMothod = null;
		if(arg1.getType() == boolean.class){
			mMothod = getBooleanFieldGetMethod(arg0, fn);
		}
		if(mMothod == null ){
			mMothod = getFieldGetMethod(arg0, fn);
		}
		return mMothod;
	}

	public static Method getBooleanFieldGetMethod(Class<?> clazz, String fieldName) {
		String mothod = "is" + StringUtil.getUpperCase(fieldName.substring(0, 1)) + fieldName.substring(1);
		if(isISStart(fieldName)){
			mothod = fieldName;
		}
		try {
			return clazz.getDeclaredMethod(mothod);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 
	 * @param fieldName
	 * @return
	 */
	private static boolean isISStart(String fieldName){
		if(fieldName==null || fieldName.trim().length()==0)
			return false;

		return fieldName.startsWith("is") && !Character.isLowerCase(fieldName.charAt(2));
	}
	
	public static Method getFieldGetMethod(Class<?> arg0, String arg1) {
		String mothod = "get" + StringUtil.getUpperCase(arg1.substring(0, 1)) + arg1.substring(1);
		try {
			return arg0.getDeclaredMethod(mothod);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 
	 * @param obj
	 * @param method
	 * @return
	 */
	private static Object invoke(Object obj , Method method){
		if(obj == null || method == null) return null;
		try {
			return method.invoke(obj);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 
	 * @param arg1
	 * @param arg2
	 * @return
	 */
	public static List<Field> getFields(Field[] arg1, Field[] arg2){
		Map<String, Field> map = new LinkedHashMap<String, Field>();
		for (Field mField : arg1){
			if (!mField.isAnnotationPresent(Column.class)){
				continue;
			}

			Column mColumn = (Column) mField.getAnnotation(Column.class);
			
			map.put(mColumn.name(), mField);
		}
		
		for (Field mField : arg2){
			if (!mField.isAnnotationPresent(Column.class)){
				continue;
			}

			Column mColumn = (Column) mField.getAnnotation(Column.class);
			
			map.put(mColumn.name(), mField);
		}
		
		List<Field> mList = new ArrayList<Field>();
		
		for (String key : map.keySet()){
			Field mField = map.get(key);
			
			if (mField.isAnnotationPresent(Id.class)){
				mList.add(0, mField);
			}
			else{
				mList.add(mField);
			}
		}
		
		return mList;
	}
	
	/**
	 * 
	 * @param fields
	 * @return
	 */
	public static String getPrimaryKeyByFields(List<Field> fields){
		for (Field field : fields){
			if(field.isAnnotationPresent(Id.class)){
				Column column = (Column) field.getAnnotation(Column.class);
				
				return column.name();
			}
		}
		
		return null;
	}
	
	public static void setFieldValue(final Object object, final String fieldName, final Object value) {  
        Field field = getDeclaredField(object, fieldName);  
  
        if (field == null) {  
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");  
        }  
  
        makeAccessible(field);  
  
        try {  
            field.set(object, value);  
        } catch (IllegalAccessException e) {  
        }  
    }  
	
	
	protected static Field getDeclaredField(final Object object, final String fieldName) {  
        for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {  
            try {  
                return superClass.getDeclaredField(fieldName);  
            } catch (NoSuchFieldException e) {
            }  
        }  
        return null;  
    }
	
    protected static void makeAccessible(final Field field) {  
        if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {  
            field.setAccessible(true);  
        }  
    }
}
